﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Perspective.Wpf3D.Primitives;
using Perspective.Wpf3D.Sculptors;

namespace Perspective.Wpf3D.Shapes
{
    /// <summary>
    /// 立方体内空棱柱形
    /// A 3D polygon in seqare element.
    /// By default, the direction of the polygon is the Z axis, and the length is 1.0.
    /// Default radius is 1.0.
    /// </summary>
    public class PrismInBox3D : GeometryElement3D
    {
         #region Constructors
         /// <summary>
        /// 正方形内接多边形
        /// Static constructor.
        /// No default back material for 3D closed shapes.
        /// </summary>
        static PrismInBox3D()
        {
            BackMaterialProperty.OverrideMetadata(
                typeof(PrismInBox3D),
                new PropertyMetadata(
                    null,
                    VisualPropertyChanged));
        }
        #endregion

        #region Properties

        #region CircumRadius 外接圆半径

        /// <summary>
        /// 外接圆半径
        /// Gets or sets the polygon circumcircle radius.
        /// Default value is 10.0.
        /// </summary>
        public double CircumRadius
        {
            get { return (double)GetValue(CircumRadiusProperty); }
            set { SetValue(CircumRadiusProperty, value); }
        }

        /// <summary>
        /// Identifies the circumcircle radius dependency property.
        /// </summary>
        public static readonly DependencyProperty CircumRadiusProperty =
            DependencyProperty.Register(
                "CircumRadius",
                typeof(double),
                typeof(PrismInBox3D),
                new UIPropertyMetadata(
                    1.0,
                    VisualPropertyChanged),
                    PositiveDoubleValidateValue);
        #endregion

        #region SideCount 侧面数
        /// <summary>
        /// 侧面数
        /// Gets or sets the model side count.
        /// Default value is 4. Minimum value is 3.
        /// </summary>
        public int SideCount
        {
            get { return (int)GetValue(SideCountProperty); }
            set { SetValue(SideCountProperty, value); }
        }

        /// <summary>
        /// Identifies the SideCount dependency property.
        /// </summary>
        public static readonly DependencyProperty SideCountProperty =
            DependencyProperty.Register(
                "SideCount",
                typeof(int),
                typeof(PrismInBox3D),
                new PropertyMetadata(
                    4,
                    VisualPropertyChanged),
                    SideCountValidateValue);

        /// <summary>
        /// Validation of the SideCount value.
        /// </summary>
        /// <param name="value">Value to test.</param>
        /// <returns>Boolean value.</returns>
        private static bool SideCountValidateValue(object value)
        {
            int i = (int)value;
            if (PolygonInSquareSculptor.DefaultIncircleSideCount % i != 0)
            {
                return false;
            }
            return i >= 3 && i<=360;
        }
        #endregion

        #region Height 高度

        /// <summary>
        /// 高度
        /// Gets or sets the model side count.
        /// Default value is 1.0. Minimum value is 0.01.
        /// </summary>
        public double Height
        {
            get { return (double)GetValue(HeightProperty); }
            set { SetValue(HeightProperty, value); }
        }

        /// <summary>
        /// Identifies the Height dependency property.
        /// </summary>
        public static readonly DependencyProperty HeightProperty =
            DependencyProperty.Register(
                "Height",
                typeof(double),
                typeof(PrismInBox3D),
                new PropertyMetadata(
                    1.0,
                    VisualPropertyChanged),
                    HeightValidateValue);

        /// <summary>
        /// Validation of the Height value.
        /// </summary>
        /// <param name="value">Value to test.</param>
        /// <returns>Boolean value.</returns>
        public static bool HeightValidateValue(object value)
        {
            double i = (double)value;
            return i >= 0.001;
        }

        #endregion

        #region InitialAngle 初始角度

        /// <summary>
        /// 初始角度
        /// Gets or sets the model's initial angle value (in degrees).
        /// Default value is 0.0.
        /// </summary>
        public int InitialAngle
        {
            get { return (int)GetValue(InitialAngleProperty); }
            set { SetValue(InitialAngleProperty, value); }
        }

        /// <summary>
        /// Identifies the InitialAngle dependency property.
        /// </summary>
        public static readonly DependencyProperty InitialAngleProperty =
            DependencyProperty.Register(
                "InitialAngle",
                typeof(int),
                typeof(PrismInBox3D),
                new PropertyMetadata(
                    0,
                    VisualPropertyChanged));

        #endregion

        #region RoundingRate 圆角的曲率

        /// <summary>
        /// Gets or sets the model's angle rounding rate.
        /// The value must be comprized between 0.0 and 0.5.
        /// Default value is 0.0.
        /// </summary>
        public double RoundingRate
        {
            get { return (double)GetValue(RoundingRateProperty); }
            set { SetValue(RoundingRateProperty, value); }
        }

        /// <summary>
        /// Identifies the RoundingRate dependency property.
        /// </summary>
        public static readonly DependencyProperty RoundingRateProperty =
            DependencyProperty.Register(
                "RoundingRate",
                typeof(double),
                typeof(PrismInBox3D),
                new PropertyMetadata(
                    0.0,
                    VisualPropertyChanged),
                    RoundingRateValidateValue);

        /// <summary>
        /// Validation of the RoundingRate value.
        /// </summary>
        /// <param name="value">Value to test.</param>
        /// <returns>Boolean value.</returns>
        private static bool RoundingRateValidateValue(object value)
        {
            double d = (double)value;
            return (d >= 0.0) && (d <= 0.5);
        }
        #endregion

        #region TexturePosition 纹理坐标位置

        /// <summary>
        /// 纹理坐标位置
        /// Gets or sets the position a a texture. Default is OnSides.
        /// </summary>
        public TexturePositions TexturePosition
        {
            get { return (TexturePositions)GetValue(TexturePositionProperty); }
            set { SetValue(TexturePositionProperty, value); }
        }

        /// <summary>
        /// Identifies the TexturePosition dependency property.
        /// </summary>
        public static readonly DependencyProperty TexturePositionProperty =
            DependencyProperty.Register(
            "TexturePosition", 
            typeof(TexturePositions),
            typeof(PrismInBox3D),
            new PropertyMetadata(TexturePositions.OnSides));

        #endregion

        #endregion

        /// <summary>
        /// Called by UIElement3D.InvalidateModel() to update the 3D model.
        /// </summary>
        protected override void OnUpdateModel()
        {
            Sculptor = new PrismInBoxSculptor(CircumRadius, Height, SideCount, InitialAngle, RoundingRate);
            (Sculptor as PrismInBoxSculptor).TexturePosition = this.TexturePosition;

            base.OnUpdateModel();
        }
    }
}
